package com.jichaoyun.sys.service.impl;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jichaoyun.model.entity.LineInfo;
import com.jichaoyun.model.entity.StationInfo;

import com.jichaoyun.model.entity.User;
import com.jichaoyun.common.enums.MyExceptiontType;
import com.jichaoyun.common.ex.MyException;
import com.jichaoyun.model.vo.StationHourVo;
import com.jichaoyun.model.vo.StationParametersVo;
import com.jichaoyun.sys.mapper.FlowHourMapper;
import com.jichaoyun.sys.mapper.LineInfoMapper;
import com.jichaoyun.sys.mapper.StationInfoMapper;
import com.jichaoyun.sys.mapper.UserMapper;
import com.jichaoyun.model.vo.ComParametersVo;
import com.jichaoyun.sys.service.IStationInfoService;
import com.jichaoyun.common.utils.ExcelStyleUtils;
import com.jichaoyun.common.model.Result;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhangzhen
 * @since 2023-11-11
 */
@Service
public class StationInfoServiceImpl extends ServiceImpl<StationInfoMapper, StationInfo> implements IStationInfoService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StationInfoMapper stationInfoMapper;

    @Autowired
    private LineInfoMapper lineInfoMapper;

    @Autowired
    private FlowHourMapper flowHourMapper;

    /**
     * 根据站点名称获取电话号码
     * @param stationName
     * @return
     */
    @Override
    public String getTelByStationName(String stationName) {

        LambdaQueryWrapper<StationInfo> wrapper  = new LambdaQueryWrapper<>();
        wrapper.eq(StationInfo::getStationName,stationName);
        StationInfo stationInfo = this.stationInfoMapper.selectOne(wrapper);

        return stationInfo.getTel();
    }

    /**
     * 增加站点信息
     * @param stationInfo
     */
    @Override
    public void addStationInfo(StationInfo stationInfo) {
        LambdaQueryWrapper<StationInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StationInfo::getStationName,stationInfo.getStationName());
        StationInfo stationInfo1 = this.stationInfoMapper.selectOne(lambdaQueryWrapper);

        if(stationInfo1 != null){
            throw new MyException(MyExceptiontType.STATIONEXIST,null);
        }else{
            this.stationInfoMapper.insert(stationInfo);
        }
    }

    /**
     * 查询用户所有站点名称
     * @param id
     * @return
     */
    @Override
    public List<Map<String,Object>> getStationNameList(Integer id) {
        User user = this.userMapper.selectById(id);
        List<Map<String,Object>> res = new ArrayList<>();

        if(user.getUserRole().equals(0)){
            //普通用户只能看到自己的站点
            LambdaQueryWrapper<StationInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(StationInfo::getUserId,id)
                    .eq(StationInfo::getIsUse,1);
            List<StationInfo> result = this.baseMapper.selectList(wrapper);
            for(StationInfo item:result){
                HashMap<String, Object> map = new HashMap<>();
                map.put("station_no",item.getStationNo());
                map.put("station_name",item.getStationName());
                res.add(map);
            }
        }else {
            QueryWrapper<StationInfo> wrapper = new QueryWrapper<>();
            wrapper.select("station_no,station_name")
                    .eq("is_use",1);
            List<StationInfo> station_list = stationInfoMapper.selectList(wrapper);
            for(StationInfo item : station_list){
                HashMap<String, Object> map = new HashMap<>();
                map.put("station_no",item.getStationNo());
                map.put("station_name",item.getStationName());
                res.add(map);
            }
        }
        return res;
    }

    /**
     * 查询用户线路分布情况
     * @return
     */
    @Override
    public Map<String, Integer> getUserLineDistribution() {
        QueryWrapper<StationInfo> wrapper = new QueryWrapper<>();
//        wrapper.select("line_id");
//        List<StationInfo> result = this.baseMapper.selectList(wrapper);
//        Map<Integer,Integer> map = new HashMap<>();
//        for(StationInfo item:result){
//            if(!map.containsKey(item.getLineId())){
//                map.put(item.getLineId(),1);
//            }else{
//                map.put(item.getLineId(), map.get(item.getLineId()) + 1);
//            }
//        }

        wrapper.select("line_id,count(*) as count")
                .groupBy("line_id");
        List<Map<String, Object>> mapList = this.baseMapper.selectMaps(wrapper);
        Map<Integer,Integer> map = new HashMap<>();
        for (Map<String, Object> objectMap : mapList) {
            map.put((Integer) objectMap.get("line_id"),(Integer) objectMap.get("count"));
        }

        Map<String,Integer> res = new HashMap<>();
        QueryWrapper<LineInfo> line_info = new QueryWrapper<>();
        line_info.select("line_num,line_name,line_alias");
        List<LineInfo> line_list = lineInfoMapper.selectList(line_info);

        for(LineInfo item : line_list){
            String lineName;
            if(item.getLineAlias() ==null || item.getLineAlias().isEmpty()){
                lineName = item.getLineName();
            }else {
                lineName = item.getLineAlias();
            }
            //没有分配不给前端展示
            if(map.containsKey(item.getLineNum())){
                Integer num = map.get(item.getLineNum());
                res.put(lineName,num);
            }
        }
        return res;
    }

    /**
     * 查询用户类别分布
     * @return
     */
    @Override
    public Map<String, Integer> getUserCategory() {
        LambdaQueryWrapper<StationInfo> major = new LambdaQueryWrapper<>();
        major.eq(StationInfo::getIsMaster,1);
        Integer major_num = this.baseMapper.selectCount(major).intValue();
        LambdaQueryWrapper<StationInfo> other = new LambdaQueryWrapper<>();
        other.eq(StationInfo::getIsMaster,0);
        Integer other_num = this.baseMapper.selectCount(other).intValue();
        Map<String,Integer> res = new HashMap<>();
        res.put("主要用户",major_num);
        res.put("普通用户",other_num);
        return res;
    }

    @Override
    public IPage<StationInfo> getAllStationInfo(Integer pageNo) {
        IPage<StationInfo> stationIPage = new Page<>(pageNo,5);
        QueryWrapper<StationInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("station_no");
        return stationInfoMapper.selectPage(stationIPage,queryWrapper);
    }

    /**
     *查找所有站点信息
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public IPage<StationInfo> getAllStationInfo(Integer pageNo,Integer pageSize) {
        IPage<StationInfo> stationIPage = new Page<>(pageNo,pageSize);
        QueryWrapper<StationInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("station_no");
        return stationInfoMapper.selectPage(stationIPage,queryWrapper);
    }
    @Override
    public List<StationInfo> getAllStationInfo(){
        QueryWrapper<StationInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("station_no");
        return stationInfoMapper.selectList(queryWrapper);
    }

    /**
     * 修改站点启用状态
     * @param stationNo
     * @return
     */
    @Override
    public Result<Object> updateStationStatus(Integer stationNo) {

        LambdaQueryWrapper<StationInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationInfo::getStationNo,stationNo);
        StationInfo result = this.baseMapper.selectOne(wrapper);
        if (result == null) {
            throw new MyException(MyExceptiontType.STATIONNOTFIND,null);
        }

        if(result.getIsUse().equals(true)){
            result.setIsUse(false);
        } else if (result.getIsUse().equals(false)) {
            result.setIsUse(true);
        }
        stationInfoMapper.updateById(result);
        return Result.success("修改成功");
    }

    /**
     * 修改站点参数信息
     * @param stationParameters
     */
    @Override
    public void updateStationInfo(StationParametersVo stationParameters) {

        if(this.getById(stationParameters.getStationNo()) == null) {
            throw new MyException(MyExceptiontType.STATIONNOTFIND, null);
        }
        LambdaQueryWrapper<StationInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StationInfo::getStationName,stationParameters.getStationName());
        StationInfo stationInfo1 = this.stationInfoMapper.selectOne(lambdaQueryWrapper);

        if(stationInfo1 != null && !Objects.equals(stationInfo1.getStationNo(), stationParameters.getStationNo())){
            throw new MyException(MyExceptiontType.STATIONEXIST,null);
        }else{
            StationInfo stationInfo = new StationInfo();

            stationInfo.setStationNo(stationParameters.getStationNo());
            stationInfo.setStationName(stationParameters.getStationName());
            stationInfo.setUserId(stationParameters.getUserId());
            stationInfo.setLineId(stationParameters.getLineId());
            stationInfo.setUserType(stationParameters.getUserType());
            stationInfo.setYbType(stationParameters.getYbType());
            stationInfo.setAddr(stationParameters.getAddr());
            stationInfo.setGprsId(stationParameters.getGprsId());
            stationInfo.setTrange(stationParameters.getTrange());
            stationInfo.setPrange(stationParameters.getPrange());
            stationInfo.setFrange(stationParameters.getFrange());
            stationInfo.setTel(stationParameters.getTel());
            stationInfo.setComType(stationParameters.getComType());
            stationInfo.setFupa(stationParameters.getFupa());
            stationInfo.setFdowna(stationParameters.getFdowna());
            stationInfo.setTupa(stationParameters.getTupa());
            stationInfo.setTdowna(stationParameters.getTdowna());
            stationInfo.setPupa(stationParameters.getPupa());
            stationInfo.setPdowna(stationParameters.getPdowna());
            stationInfo.setIsMaster(stationParameters.getIsMaster());
            stationInfo.setMinConsume(stationParameters.getMinConsume());
            stationInfo.setBalance(stationParameters.getBalance());
            stationInfo.setBalanceAlarm(stationParameters.getBalanceAlarm());
            stationInfo.setMaxOverdraft(stationParameters.getMaxOverdraft());
            stationInfo.setSentTimeStart(stationParameters.getSentTimeStart());
            stationInfo.setSentTimeEnd(stationParameters.getSentTimeEnd());
            stationInfo.setComPassword(stationParameters.getComPassword());
            stationInfo.setFreupa(stationParameters.getFreupa());
            stationInfo.setFredowna(stationParameters.getFredowna());
            stationInfo.setBankCardNumber(stationParameters.getBankCardNumber());
            stationInfoMapper.updateById(stationInfo);
        }

    }

    /**
     * 修改站点通讯参数信息
     * @param comParameters
     */
    @Override
    public void updateComParameters(ComParametersVo comParameters) {
        UpdateWrapper<StationInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("com_ip",comParameters.getComIp());
        updateWrapper.set("com_port",comParameters.getComPort());
        updateWrapper.set("tcp_addr",comParameters.getTcpAddr());
        updateWrapper.set("udp_addr",comParameters.getUdpAddr());
        updateWrapper.set("account_hour",comParameters.getAccountHour());
        updateWrapper.set("account_date",comParameters.getAccountDate());
        updateWrapper.set("storage_time",comParameters.getStorageTime());
        updateWrapper.set("collection_circle",comParameters.getCollectionCircle());
        updateWrapper.set("storage_circle",comParameters.getStorageCircle());
        updateWrapper.set("instruct_circle",comParameters.getInstructCircle());

        stationInfoMapper.update(null,updateWrapper);
    }

    @Override
    public String getLineNameByStationNo(Integer station_no) {
        StationInfo res = stationInfoMapper.selectById(station_no);
        LambdaQueryWrapper<LineInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LineInfo::getLineNum,res.getLineId());
        LineInfo result = lineInfoMapper.selectOne(wrapper);
        if(result.getLineAlias().isEmpty() || result == null){
            return result.getLineName();
        }
        return result.getLineAlias();
    }

    /**
     * 根据日期返回当日流速排名
     * @param date
     * @return
     */
    @Override
    public Map<String, Float> getFlowRankListByDate(LocalDate date) {
        //根据日期查询小时表流速
        List<StationHourVo> list = this.flowHourMapper.selectStationHourList(date,date.plusDays(1));

        Map<String,Float> res = new HashMap<>();
        Map<String,Integer> cnt = new HashMap<>();

        //  求出 站点 流速和 存入res，站点 记录条数 存入cnt
        for(int i = 0;i < list.size(); i ++){
            StationHourVo stationInfo = list.get(i);
            if(stationInfo == null) {
                continue;
            }
            String stationName = stationInfo.getStationName();
            Float item = stationInfo.getFlowStart();
            if(item == null){
                item = 0F;
            }
          
            if(res.containsKey(stationName)){
                res.putIfAbsent(stationName, 0F);
                Float t = res.get(stationName);
                Integer tt = cnt.get(stationName);
                res.put(stationName, t + item);
                cnt.put(stationName, tt + 1);
            }else{
                res.put(stationName,item);
                cnt.put(stationName,1);
            }
        }

        //遍历res与cnt 将平均流速求出来存入result
        Map<String,Float> result = new HashMap<>();
        for (String key : res.keySet()) {
            result.put(key,res.get(key) / cnt.get(key));
        }

        //对result按value从大到小排序
        LinkedHashMap<String,Float> resultMap = result.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (s, s2) -> s, LinkedHashMap::new));

        //取出排名前十的数据
        LinkedHashMap<String,Float> resultMap1 = new LinkedHashMap<>();
        int i = 0;
        for(String key : resultMap.keySet()){
            if(i >= 10){
                break;
            }
            i ++;
            resultMap1.put(key,resultMap.get(key));
        }
        return resultMap1;
    }

    /**
     * 根据日期返回当日平均温度排名
     * @param date
     * @return
     */
    @Override
    public Map<String, Float> getTempRankListByDate(LocalDate date) {
        //根据日期查询小时表温度
        List<StationHourVo> list = this.flowHourMapper.selectStationHourList(date,date.plusDays(1));

        Map<String,Float> res = new HashMap<>();
        Map<String,Integer> cnt = new HashMap<>();

        //  求出 站点 温度和 存入res，站点 记录条数 存入cnt
        for(int i = 0;i < list.size(); i ++){
            StationHourVo stationInfo = list.get(i);
            if(stationInfo == null) {
                continue;
            }
            String stationName = stationInfo.getStationName();
            Float item = stationInfo.getTempStart();
            if(item == null){
                item = 0F;
            }

            if(res.containsKey(stationName)){
                res.putIfAbsent(stationName, 0F);
                Float t = res.get(stationName);
                Integer tt = cnt.get(stationName);
                res.put(stationName, t + item);
                cnt.put(stationName, tt + 1);
            }else{
                res.put(stationName,item);
                cnt.put(stationName,1);
            }
        }

        //遍历res与cnt 将平均温度求出来存入result
        Map<String,Float> result = new HashMap<>();
        for (String key : res.keySet()) {
            result.put(key,res.get(key) / cnt.get(key));
        }

        //对result按value从大到小排序
        LinkedHashMap<String,Float> resultMap = result.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (s, s2) -> s, LinkedHashMap::new));

        //取出排名前十的数据
        LinkedHashMap<String,Float> resultMap1 = new LinkedHashMap<>();
        int i = 0;
        for(String key : resultMap.keySet()){
            if(i >= 10) break;
            i ++;
            resultMap1.put(key,resultMap.get(key));
        }
        return resultMap1;
    }

    /**
     * 根据日期返回当日平均压力排名
     * @param date
     * @return
     */
    @Override
    public Map<String, Float> getPresRankListByDate(LocalDate date) {
        //根据日期查询小时表压力
        List<StationHourVo> list = this.flowHourMapper.selectStationHourList(date,date.plusDays(1));

        Map<String,Float> res = new HashMap<>();
        Map<String,Integer> cnt = new HashMap<>();

        //  求出 站点 压力和 存入res，站点 记录条数 存入cnt
        for(int i = 0;i < list.size(); i ++){
            StationHourVo stationInfo = list.get(i);
            if(stationInfo == null) {
                continue;
            }
            String stationName = stationInfo.getStationName();
            Float item = stationInfo.getPresStart();
            if(item == null){
                item = 0F;
            }

            if(res.containsKey(stationName)){
                res.putIfAbsent(stationName, 0F);
                Float t = res.get(stationName);
                Integer tt = cnt.get(stationName);
                res.put(stationName, t + item);
                cnt.put(stationName, tt + 1);
            }else{
                res.put(stationName,item);
                cnt.put(stationName,1);
            }
        }

        //遍历res与cnt 将平均压力求出来存入result
        Map<String,Float> result = new HashMap<>();
        for (String key : res.keySet()) {
            result.put(key,res.get(key) / cnt.get(key));
        }

        //对result按value从大到小排序
        LinkedHashMap<String,Float> resultMap = result.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (s, s2) -> s, LinkedHashMap::new));

        //取出排名前十的数据
        LinkedHashMap<String,Float> resultMap1 = new LinkedHashMap<>();
        int i = 0;
        for(String key : resultMap.keySet()){
            if(i >= 10) break;
            i ++;
            resultMap1.put(key,resultMap.get(key));
        }
        return resultMap1;
    }

    /**
     * 设置报表结算的小时和日期
     * @param id
     * @param account_date
     * @param account_hour
     */
    @Override
    public void updateAccountDateAndHour(Integer id,Integer account_date, Integer account_hour) {
        StationInfo stationInfo = new StationInfo();
        stationInfo.setStationNo(id);
        stationInfo.setAccountDate(account_date);
        stationInfo.setAccountHour(account_hour);
        int result =stationInfoMapper.updateById(stationInfo);
        if(result!=1){
            throw new MyException(MyExceptiontType.UPDATEERROR,null);
        }
    }

    @Override
    public Integer getAccountHourByStation(Integer station_no) {
        LambdaQueryWrapper<StationInfo> w = new LambdaQueryWrapper<>();
        StationInfo stationInfo = this.baseMapper.selectById(station_no);
        return stationInfo.getAccountHour();
    }

    @Override
    public Integer getAccountDateByStation(Integer station_no) {
        LambdaQueryWrapper<StationInfo> w = new LambdaQueryWrapper<>();
        StationInfo stationInfo = this.baseMapper.selectById(station_no);
        return stationInfo.getAccountDate();
    }

    @Override
    public List<String> getStationNoNameListByLikeName(String likeName) {
        if(likeName == null){
            likeName = "";
        }
        LambdaQueryWrapper<StationInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StationInfo::getStationName,likeName);
//                .eq(StationInfo::getIsUse,1);
        List<StationInfo> stationInfoList = stationInfoMapper.selectList(wrapper);

        ArrayList<String> res = new ArrayList<>();
        for (StationInfo stationInfo : stationInfoList) {
            res.add(stationInfo.getStationNo()+" "+stationInfo.getStationName());
        }
        return res;
    }

    @Override
    public List<StationInfo> getAllUsedStation() {
        LambdaQueryWrapper<StationInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationInfo::getIsUse,1);
        return stationInfoMapper.selectList(wrapper);
    }

    /**
     * 查询所有非叶子节点
     * @return
     */
    @Override
    public List<StationInfo> getAllLineStation() {
        LambdaQueryWrapper<StationInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationInfo::getIsLeaf,0);
        return stationInfoMapper.selectList(wrapper);
    }

    /**
     * 所有站点信息表，导出到Excel
     * @param response
     * @throws IOException
     */
    @Override
    public void getAllStationExcel(HttpServletResponse response) throws IOException {

        List<StationInfo> resList = getAllStationInfo();

        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("站点信息表", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(ExcelStyleUtils.getHeadStyle(), ExcelStyleUtils.getContentStyle());

            // 这里需要设置不关闭流
            EasyExcel.write(response.getOutputStream(), StationInfo.class)
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .autoCloseStream(Boolean.FALSE)
                    .sheet("sheet1")
                    .doWrite(resList);

        } catch (Exception e) {
            // 重置response
//            throw  e;
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");

            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSONUtils.toJSONString(map));
            throw new MyException(MyExceptiontType.FILEDOWNLOADFAIL,"下载文件失败");
        }
    }
}
